/****************************************************************************
 * Copyright (C) 2009-2010 SciTouch LLC
 *
 * This file is part of Indigo toolkit.
 *
 * This file may be distributed and/or modified under the terms of the
 * GNU General Public License version 3 as published by the Free Software
 * Foundation and appearing in the file LICENSE.GPL included in the
 * packaging of this file.
 *
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 ***************************************************************************/

package com.indigo;

import java.io.IOException;
import java.io.FileOutputStream;
import java.io.File;

public class Dingo
{
   public Dingo (String path)
   {
      path = path + File.separator + _dllpath;

      String fullpath = path;
      try
      {
         fullpath = (new File(path)).getCanonicalPath();
      }
      catch (Exception e)
      {
      }

      if (_os == OS_LINUX)
         System.load(fullpath + File.separator + "libdingojni.so");
      else if (_os == OS_MACOS)
         System.load(fullpath + File.separator + "libdingojni.dylib");
      else // _os == OS_WINDOWS
      {
         if (_arch == X64)
            System.load(fullpath + File.separator + "libgcc_s_1.dll");
         System.load(fullpath + File.separator + "zlib1.dll");
         System.load(fullpath + File.separator + "libpng12-0.dll");
         System.load(fullpath + File.separator + "libcairo-2.dll");
         System.load(fullpath + File.separator + "dingo.dll");
         System.load(fullpath + File.separator + "dingojni.dll");
      }

      _sid = allocSessionId();
   }

   public Dingo ()
   {
      this("lib");
   }

   @Override
   protected void finalize () throws Throwable
   {
      releaseSessionId(_sid);
   }
   
   public native int versionCode ();
   public native String versionRevisionString ();

   private static native long allocSessionId ();
   private static native void releaseSessionId (long id);

   public native void beginLog (String path);
   public native void endLog ();

   public native void loadMolFromFile (String filename);
   public native void loadMolFromBuffer (byte[] buf);
   public native void loadMolFromString (String str);
   public native void loadReactionFromFile (String filename);
   public native void loadReactionFromBuffer (byte[] buf);
   public native void loadReactionFromString (String str);
   public native void setOutputFormat (String format);
   public native void setOutputFile (String filename);
   public native boolean moleculeIsEmpty ();
   public native boolean reactionIsEmpty ();
   public native void setImageSize (int w, int h);
   public native void setBondLength (float len);
   public native void setOptions (String options);
   public native void setOption (String name, String value);
   private native void setOptionSize (String name, int w, int h);
   private native void setOptionEnabled (String name, int enabled);
   private native void setOptionFloat (String name, float value);
   private native void setOptionColor (String name, float r, float g, float b);

   public native void render ();
   public native void layout ();
   public native void reset ();
   public native byte[] getResult ();

   public void setOption (String name, boolean value)
   {
      setOptionEnabled(name, value ? 1 : 0);
   }
   public void setOption (String name, float value)
   {
      setOptionFloat(name, value);
   }
   public void setOption (String name, float r, float g, float b)
   {
      setOptionColor(name, r, g, b);
   }
   public void setOption (String name, int w, int h)
   {
      setOptionSize(name, w, h);
   }

   private long _sid;

   ////////////////////////////////////////////////////////////////
   // INITIALIZATION
   ////////////////////////////////////////////////////////////////
   private static final int OS_WINDOWS = 1;
   private static final int OS_MACOS = 2;
   private static final int OS_LINUX = 3;
   private static final int X86 = 32;
   private static final int X64 = 64;
   private static int _arch = 0;
   private static int _os = 0;
   private static String _dllpath = "";

   private static int getArch ()
   {
       String archstr = System.getProperty("os.arch");
       if (archstr.equals("x86") || archstr.equals("i386"))
           return X86;
       else if (archstr.equals("x86_64") || archstr.equals("amd64"))
           return X64;
       else
           throw new Error("Platform not unrecognized");
   }

   private static int getOs ()
   {
      String namestr = System.getProperty("os.name");
       if (namestr.matches("^Windows.*"))
           return OS_WINDOWS;
       else if (namestr.matches("^Mac OS.*"))
           return OS_MACOS;
       else if (namestr.matches("^Linux.*"))
           return OS_LINUX;
       else
           throw new Error("Operating system not unrecognized");
   }

   private static String getDllPath ()
   {
      String path = "";
      switch (_os)
      {
         case OS_WINDOWS:
            path += "Win";
            break;
         case OS_LINUX:
            path += "Linux";
            break;
         case OS_MACOS:
            path += "Mac";
            break;
         default:
            throw new Error("OS not set");
      }
      path += File.separator;

      if (_os == OS_MACOS)
      {
         String version = System.getProperty("os.version");
         
         if (version.startsWith("10.5"))
            path += "10.5";
         else if (version.startsWith("10.6"))
            path += "10.6";
         else
            throw new Error("OS version not supported");
      } else 
      {
         switch (_arch)
         {
            case X86:
               path += "x86";
               break;
            case X64:
               path += "x64";
               break;
            default:
               throw new Error("Platform not set");
         }
      }

      return path;
   }
   
   static
   {
      _arch = getArch();
      _os = getOs();
      _dllpath = getDllPath();
   }

   ////////////////////////////////////////////////////////////////
   // TEST CODE
   ////////////////////////////////////////////////////////////////
   public static void main (String[] args) throws IOException
   {
        //System.in.read();
        Dingo dingo = new Dingo();
        Dingo dingo2 = new Dingo();
        Dingo dingo3 = new Dingo();
        Dingo dingo4 = new Dingo();
        System.out.println(dingo.versionRevisionString());

        dingo.setOption("output-format", "png");
        dingo.setBondLength(50);
        dingo.setOption("base-color", 0.0f, 0.5f, 0.2f);

        dingo2.setOptions("output-format=png; output-file=test/d2.png");
        dingo.setOption("base-color", 0.0f, 0.5f, 0.2f);
        dingo.loadMolFromString("C1=CC=NC=C1");
        dingo2.loadMolFromFile("test/test2.smi");
        dingo2.setOption("image-size", "100,100");
        if (dingo.moleculeIsEmpty())
           System.out.println("Empty molecule");
        dingo3.loadReactionFromString("C1=CC=NC=C1>>CNCNCNCNC");
        dingo3.setOutputFormat("svg");
        dingo3.setOutputFile("test/d3.svg");
        dingo3.setImageSize(500, 300);
        dingo.render();
        dingo2.render();
        dingo3.render();
        byte[] bytes = dingo.getResult();
        System.out.println(bytes.length);
        FileOutputStream w = new FileOutputStream("test/d1.png");
        w.write(bytes);
        w.close();

        dingo4.setOptions("output-format=png; output-file=test/d4.png; bond-length=50; base-color=0,0.5,0.2");
        dingo4.loadMolFromString("C1=CC=NC=C1");
        dingo4.render();
   }
}
